package pl.wroc.uni.ii.evolution.servlets.databasesupport.providers;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import pl.wroc.uni.ii.evolution.engine.operators.general.statistic.EvStatistic;
import pl.wroc.uni.ii.evolution.servlets.databasesupport.structure.EvIndividualInfo;
import pl.wroc.uni.ii.evolution.servlets.databasesupport.structure.EvTaskInfo;

public class EvMySQLDatabaseProvider implements EvDatabaseProvider {

  private Connection conn;

  /** *************************************************************************** */

  public void connect(String database_url, String database_user,
      String database_password) throws SQLException {
    DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    
    conn = DriverManager.getConnection(database_url, database_user,
        database_password);
    conn.setAutoCommit(false);
    PreparedStatement stmt = conn.prepareStatement("USE evolve;");
    stmt.execute();
    conn.commit();
  }

  public void disconnect() throws SQLException {
    conn.close();
  }

  /** *************************************************************************** */

  private byte[] toByteArray(Object ob) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
      ObjectOutputStream os = new ObjectOutputStream(baos);
      os.writeObject(ob);
      return baos.toByteArray();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  public int addIndividual(Object individual, long task_id,
      double objective_value, long cell_id, long node_id) throws IOException {
    int ID = -1;

    try {

      PreparedStatement stmt = conn
          .prepareStatement(
              "INSERT INTO individual(instance_id, objective_value, individual, creation_cell, creation_node) VALUES("
                  + task_id
                  + ","
                  + objective_value
                  + ", ?, "
                  + cell_id
                  + ","
                  + node_id + ")", Statement.RETURN_GENERATED_KEYS);

      stmt.setBytes(1, toByteArray(individual));
      stmt.execute();
      conn.commit();

      ResultSet rs = stmt.getGeneratedKeys();

      if (rs.next()) {

        ID = rs.getInt(1);
      }

    } catch (SQLException e) {
      e.printStackTrace();
    }
    return ID;
  }

  /** *************************************************************************** */

  public boolean deleteIndividual(int id) throws IOException {
    boolean done = false;
    try {
      Statement stmt = conn.createStatement();
      String s = "DELETE FROM individual WHERE id = " + id;
      stmt.execute(s);
      conn.commit();
      stmt.close();
      done = true;
    } catch (SQLException e) {
      e.printStackTrace();
    }
    return done;
  }

  /** *************************************************************************** */

  public EvIndividualInfo getIndividualInfo(int id,
      boolean with_individual_itself) throws IOException {
    EvIndividualInfo info = null;

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM individual WHERE id = " + id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next()) {
        info = new EvIndividualInfo();
        info.setID(rs.getInt("id"));
        info.setTaskID(rs.getLong("instance_id"));
        info.setObjectiveValue(rs.getDouble("objective_value"));
        info.setCellID(rs.getLong("creation_cell"));
        info.setNodeID(rs.getLong("creation_node"));
        info.setCreationTime(rs.getTimestamp("creation_time"));

        if (with_individual_itself) {
          Blob blob = rs.getBlob("individual");
          ObjectInputStream input = new ObjectInputStream(blob
              .getBinaryStream());
          info.setIndividual(input.readObject());
        }
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (ClassNotFoundException e) {
      e.printStackTrace(System.out);
    }

    catch (Exception ex) {
      ex.printStackTrace(System.out);
    }

    return info;
  }

  /** *************************************************************************** */

  public EvIndividualInfo[] getBestIndividualInfos(long task_id, int k, int n,
      boolean with_individuals_itselves) throws IOException {
    EvIndividualInfo[] infos = new EvIndividualInfo[n];

    try {
      int i = 0;

      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM (SELECT * FROM individual WHERE instance_id = "
          + task_id + " ORDER BY objective_value DESC) AS cos LIMIT " + (k - 1)
          + " ," + n;
      ResultSet rs = stmt.executeQuery(s);

      while (rs.next()) {
        infos[i] = new EvIndividualInfo();
        infos[i].setID(rs.getInt("id"));
        infos[i].setTaskID(rs.getLong("instance_id"));
        infos[i].setObjectiveValue(rs.getDouble("objective_value"));
        infos[i].setCellID(rs.getLong("creation_cell"));
        infos[i].setNodeID(rs.getLong("creation_node"));
        infos[i].setCreationTime(rs.getTimestamp("creation_time"));

        if (with_individuals_itselves) {
          Blob blob = rs.getBlob("individual");
          ObjectInputStream input = new ObjectInputStream(blob
              .getBinaryStream());
          infos[i].setIndividual(input.readObject());
        }

        i++;
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    return infos;
  }

  public EvIndividualInfo[] getBestIndividualInfosMatchingCell(long task_id,
      long cell_id, int k, int n, boolean with_individuals_itselves)
      throws IOException {
    EvIndividualInfo[] infos = new EvIndividualInfo[n];

    try {
      int i = 0;

      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM (SELECT * FROM individual WHERE instance_id = "
          + task_id + " AND creation_cell = " + cell_id
          + " ORDER BY objective_value DESC) AS cos LIMIT " + (k - 1) + " ,"
          + n;
      ResultSet rs = stmt.executeQuery(s);

      while (rs.next()) {
        infos[i] = new EvIndividualInfo();
        infos[i].setID(rs.getInt("id"));
        infos[i].setTaskID(rs.getLong("instance_id"));
        infos[i].setObjectiveValue(rs.getDouble("objective_value"));
        infos[i].setCellID(rs.getLong("creation_cell"));
        infos[i].setNodeID(rs.getLong("creation_node"));
        infos[i].setCreationTime(rs.getTimestamp("creation_time"));

        if (with_individuals_itselves) {
          Blob blob = rs.getBlob("individual");
          ObjectInputStream input = new ObjectInputStream(blob
              .getBinaryStream());
          infos[i].setIndividual(input.readObject());
        }

        i++;
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    return infos;
  }

  public EvIndividualInfo[] getBestIndividualInfosNotMatchingCell(long task_id,
      long cell_id, int k, int n, boolean with_individuals_itselves)
      throws IOException {
    EvIndividualInfo[] infos = new EvIndividualInfo[n];

    try {
      int i = 0;

      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM (SELECT * FROM individual WHERE instance_id = "
          + task_id + " AND creation_cell <> " + cell_id
          + " ORDER BY objective_value DESC) AS cos LIMIT " + (k - 1) + " ,"
          + n;
      ResultSet rs = stmt.executeQuery(s);

      while (rs.next()) {
        infos[i] = new EvIndividualInfo();
        infos[i].setID(rs.getInt("id"));
        infos[i].setTaskID(rs.getLong("instance_id"));
        infos[i].setObjectiveValue(rs.getDouble("objective_value"));
        infos[i].setCellID(rs.getLong("creation_cell"));
        infos[i].setNodeID(rs.getLong("creation_node"));
        infos[i].setCreationTime(rs.getTimestamp("creation_time"));

        if (with_individuals_itselves) {
          Blob blob = rs.getBlob("individual");
          ObjectInputStream input = new ObjectInputStream(blob
              .getBinaryStream());
          infos[i].setIndividual(input.readObject());
        }

        i++;
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    return infos;
  }

  public EvIndividualInfo[] getBestIndividualInfosMatchingNode(long task_id,
      long cell_id, int k, int n, boolean with_individuals_itselves)
      throws IOException {
    EvIndividualInfo[] infos = new EvIndividualInfo[n];

    try {
      int i = 0;

      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM (SELECT * FROM individual WHERE instance_id = "
          + task_id + " AND creation_node = " + cell_id
          + " ORDER BY objective_value DESC) AS Cos LIMIT " + (k - 1) + " ,"
          + n;
      ResultSet rs = stmt.executeQuery(s);

      while (rs.next()) {
        infos[i] = new EvIndividualInfo();
        infos[i].setID(rs.getInt("id"));
        infos[i].setTaskID(rs.getLong("instance_id"));
        infos[i].setObjectiveValue(rs.getDouble("objective_value"));
        infos[i].setCellID(rs.getLong("creation_cell"));
        infos[i].setNodeID(rs.getLong("creation_node"));
        infos[i].setCreationTime(rs.getTimestamp("creation_time"));

        if (with_individuals_itselves) {
          Blob blob = rs.getBlob("individual");
          ObjectInputStream input = new ObjectInputStream(blob
              .getBinaryStream());
          infos[i].setIndividual(input.readObject());
        }

        i++;
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    return infos;
  }

  /** *************************************************************************** */

  public int getIndividualCount(long task_id) throws IOException {
    int count = -1;

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT COUNT(*) FROM individual WHERE instance_id = "
          + task_id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next())
        count = rs.getInt(1);

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return count;
  }

  public int getIndividualCountMatchingCell(long task_id, long cell_id)
      throws IOException {
    int count = -1;

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT COUNT(*) FROM individual WHERE instance_id = "
          + task_id + "AND creation_cell = " + cell_id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next())
        count = rs.getInt(1);

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return count;
  }

  public int getIndividualCountNotMatchingCell(long task_id, long cell_id)
      throws IOException {
    int count = -1;

    try {

      Statement stmt = conn.createStatement();
      String s = "SELECT COUNT(*) FROM individual WHERE instance_id = "
          + task_id + "AND creation_cell <> " + cell_id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next())
        count = rs.getInt(1);

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return count;
  }

  public int getIndividualCountMatchingNode(long task_id, long cell_id)
      throws IOException {
    int count = -1;

    try {

      Statement stmt = conn.createStatement();
      String s = "SELECT COUNT(*) FROM individual WHERE instance_id = "
          + task_id + "AND creation_node = " + cell_id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next())
        count = rs.getInt(1);

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return count;
  }

  public void deleteIndividualsFromTask(long task_id) throws IOException {
    try {
      Statement stmt = conn.createStatement();
      String s = "DELETE FROM individual WHERE instance_id=" + task_id;
      stmt.execute(s);
      conn.commit();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

  public int addSolutionSpace(long task_id, long cell_id, Object space)
      throws IOException {
    int ID = -1;

    try {

      PreparedStatement stmt = conn
          .prepareStatement(
              "INSERT INTO solutionspaces(instance_id,  cell_id, solution_space) VALUES(?, ?, ?)",
              Statement.RETURN_GENERATED_KEYS);

      stmt.setLong(1, task_id);
      stmt.setLong(2, cell_id);
      stmt.setBytes(3, toByteArray(space));
      stmt.execute();
      conn.commit();

      ResultSet rs = stmt.getGeneratedKeys();

      if (rs.next()) {

        ID = rs.getInt(1);
      }

    } catch (SQLException e) {
      e.printStackTrace();
    }
    return ID;

  }

  public Object getSolutionSpace(long task_id, long cell_id) throws IOException {

    Object space = null;

    try {

      Statement stmt = conn.createStatement();
      String s = "SELECT solution_space FROM solutionspaces WHERE iteration = (SELECT MAX(iteration) FROM solutionspaces WHERE instance_id="
          + task_id + " AND cell_id=" + cell_id + ")";
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next()) {
        Blob blob = rs.getBlob(1);
        ObjectInputStream input = new ObjectInputStream(blob.getBinaryStream());
        space = input.readObject();
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    return space;
  }

  public boolean deleteSolutionSpaces(long task_id) throws IOException {
    try {
      Statement stmt = conn.createStatement();
      String s = "DELETE FROM solutionspaces WHERE instance_id=" + task_id;
      stmt.execute(s);
      conn.commit();
      stmt.close();
      return true;
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return false;
  }

  public Long[] getTaskIDs() {
    ArrayList<Long> list = new ArrayList<Long>();

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT DISTINCT instance_id FROM individual";
      ResultSet rs = stmt.executeQuery(s);

      while (rs.next()) {
        list.add(rs.getLong(1));
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    if (list.size() != 0) {
      Long[] res = new Long[list.size()];

      for (int i = 0; i < list.size(); i++) {
        res[i] = list.get(i);
      }

      return res;
    }

    return null;
  }

  public int getVersionOfNewSolutonSpace(long task_id, long cell_id) {
    int count = 0;

    try {

      Statement stmt = conn.createStatement();
      String s = "SELECT MAX(iteration) FROM solutionspaces WHERE instance_id="
          + task_id + " AND cell_id=" + cell_id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next())
        count = rs.getInt(1);

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return count;
  }

  public EvTaskInfo getTaskForSystem(int id) throws IOException {
    EvTaskInfo info = null;

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM tasks WHERE id=" + id;
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next()) {

        Blob blob = rs.getBlob("jar");
        byte[] o = new byte[(int) blob.length()];
        blob.getBinaryStream().read(o);
        info = new EvTaskInfo();
        info.setId(rs.getInt("id"));
        info.setJar(o);
        info.setStatus(rs.getInt("status"));
        info.setDescription(rs.getString("description"));
        info.setSubmissionTime(rs.getTimestamp("submission_time"));

      }
      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }
    return info;
  }

  public int addTaskForSystem(byte[] file, String desc) throws IOException {

    int ID = -1;

    try {

      PreparedStatement stmt = conn.prepareStatement(
          "INSERT INTO tasks(jar, status, description) VALUES(?, 1, ?)",
          Statement.RETURN_GENERATED_KEYS);
      stmt.setBytes(1, file);
      stmt.setString(2, desc);
      stmt.execute();
      conn.commit();

      ResultSet rs = stmt.getGeneratedKeys();

      if (rs.next()) {

        ID = rs.getInt(1);
      }

    } catch (SQLException e) {
      e.printStackTrace();
    }
    return ID;
  }

  public void deleteTaskFromSystem(int id) throws IOException {
    try {
      Statement stmt = conn.createStatement();
      String s = "DELETE FROM tasks WHERE id = " + id;
      stmt.execute(s);
      conn.commit();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

  public Integer[] getTaskIDsForSystem() throws IOException {
    ArrayList<Integer> list = new ArrayList<Integer>();

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT id FROM tasks";
      ResultSet rs = stmt.executeQuery(s);

      while (rs.next()) {
        list.add(rs.getInt(1));
      }

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    if (list.size() != 0) {
      Integer[] res = new Integer[list.size()];

      for (int i = 0; i < list.size(); i++) {
        res[i] = list.get(i);
      }

      return res;
    }

    return null;
  }

  public void changeTaskState(int id, int state) throws IOException {
    try {
      Statement stmt = conn.createStatement();
      String s = "UPDATE tasks SET status=" + state + " WHERE id = " + id;
      stmt.execute(s);
      conn.commit();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }

  }

  /** ----- */
  public boolean deleteResource(String name) throws IOException {
    boolean done = false;
    try {
      Statement stmt = conn.createStatement();
      String s = "DELETE FROM resources WHERE name ='" + name + "'";
      stmt.execute(s);
      conn.commit();
      stmt.close();
      done = true;
    } catch (SQLException e) {
    }

    return done;
  }

  public Object getResource(String name) throws IOException {
    Object res = null;

    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM resources WHERE name='" + name + "'";
      ResultSet rs = stmt.executeQuery(s);

      if (rs.next()) {

        Blob blob = rs.getBlob("resource");

        ObjectInputStream input = new ObjectInputStream(blob.getBinaryStream());
        res = input.readObject();

      }
      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }
    return res;

  }

  public String[] getResourceNames() throws IOException {

    List<String> list;
    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT name FROM resources";
      ResultSet rs = stmt.executeQuery(s);

      list = new ArrayList<String>();
      while (rs.next()) {
        list.add(rs.getString(1));
      }

    } catch (SQLException ex) {
      ex.printStackTrace(System.out);
      return null;
    }

    if (list.size() != 0) {
      String[] res = new String[list.size()];

      for (int i = 0; i < list.size(); i++) {
        res[i] = list.get(i);
      }
      return res;
    } else {
      return null;
    }
  }

  public boolean setResource(Object res, String name) throws IOException {
    if (deleteResource(name) == false) {
      return false;
    }

    boolean done = false;

    try {

      PreparedStatement stmt = conn
          .prepareStatement("INSERT INTO resources(name,  resource) VALUES(?, ?)");

      stmt.setString(1, name);
      stmt.setBytes(2, toByteArray(res));
      stmt.execute();
      conn.commit();

    } catch (SQLException e) {
      e.printStackTrace(System.out);
    }
    return done;

  }

  /** ------------------* */
  /** -- STATISTICS --* */
  /** ------------------* */
  public Long[] getCellIdsWithStatistics(long task_id) {
    List<Long> list;
    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT DISTINCT cell_id FROM ev_statistics WHERE task_id="
          + task_id;
      ResultSet rs = stmt.executeQuery(s);

      list = new ArrayList<Long>();
      while (rs.next()) {
        list.add(rs.getLong(1));
      }
    } catch (SQLException ex) {
      ex.printStackTrace(System.out);
      return null;
    }

    if (list.size() != 0) {
      Long[] res = new Long[list.size()];

      for (int i = 0; i < list.size(); i++) {
        res[i] = list.get(i);
      }
      return res;
    } else {
      return null;
    }

  }

  public Long[] getNodesIdsWithStatistics(long task_id, long cell_id) {
    List<Long> list;
    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT DISTINCT node_id FROM ev_statistics WHERE task_id='"
          + task_id + "' AND cell_id='" + cell_id + "'";
      ResultSet rs = stmt.executeQuery(s);

      list = new ArrayList<Long>();
      while (rs.next()) {
        list.add(rs.getLong(1));
      }
    } catch (SQLException ex) {
      ex.printStackTrace(System.out);
      return null;
    }

    if (list.size() != 0) {
      Long[] res = new Long[list.size()];

      for (int i = 0; i < list.size(); i++) {
        res[i] = list.get(i);
      }
      return res;
    } else {
      return null;
    }

  }

  public Long[] getTaskIdsWithStatistics() {
    List<Long> list;
    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT DISTINCT task_id FROM ev_statistics";
      ResultSet rs = stmt.executeQuery(s);

      list = new ArrayList<Long>();
      while (rs.next()) {
        list.add(rs.getLong(1));
      }
    } catch (SQLException ex) {
      ex.printStackTrace(System.out);
      return null;
    }

    if (list.size() != 0) {
      Long[] res = new Long[list.size()];

      for (int i = 0; i < list.size(); i++) {
        res[i] = list.get(i);
      }
      return res;
    } else {
      return null;
    }
  }

  public void saveStatistic(long task_id, long cell_id, long node_id,
      Object stat, long iteration, long time) {

    try {

      PreparedStatement stmt = conn
          .prepareStatement("INSERT INTO ev_statistics(task_id, cell_id, node_id, iteration, ev_stat, node_time) VALUES(?, ?, ?, ?, ?, ?)");

      stmt.setLong(1, task_id);
      stmt.setLong(2, cell_id);
      stmt.setLong(3, node_id);
      stmt.setLong(4, iteration);
      stmt.setBytes(5, toByteArray(stat));
      stmt.setLong(6, time);
      stmt.execute();
      conn.commit();

    } catch (SQLException e) {
      e.printStackTrace(System.out);
    }

  }

  public void deleteStatisticForTask(long task_id) {
    try {
      Statement stmt = conn.createStatement();
      String s = "DELETE FROM ev_statistics WHERE task_id = '" + task_id + "'";
      stmt.execute(s);
      conn.commit();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    }
  }

  public Object[] getStatistics(long task_id, long cell_id, long node_id) {

    List<Object> result = new ArrayList<Object>();
    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM ev_statistics WHERE node_id='" + node_id
          + "' and cell_id='" + cell_id + "' and task_id='" + task_id + "'";
      ResultSet rs = stmt.executeQuery(s);
      while (rs.next()) {

        Blob blob = rs.getBlob("ev_stat");

        ObjectInputStream input = new ObjectInputStream(blob.getBinaryStream());
        result.add(input.readObject());

      }
      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }

    if (result.size() == 0) {
      return null;
    } else {
      Object[] res = new Object[result.size()];

      for (int i = 0; i < res.length; i++) {
        res[i] = result.get(i);
      }
      return res;
    }
  }

  public Object[] getStatisticsByCells(long task_id, int[] cells) {

    List<Object> result = new ArrayList<Object>();
    try {

      if (cells.length == 0)
        return null;
      String sql_str = "( cell_id=" + cells[0];
      for (int i = 1; i < cells.length; i++) {
        sql_str += " OR cell_id=" + cells[i];
      }
      sql_str += " )";

      Statement stmt = conn.createStatement();

      String s = "SELECT * FROM ev_statistics WHERE " + "task_id='" + task_id
          + "' AND " + sql_str + " ORDER BY iteration, node_id";

      ResultSet rs = stmt.executeQuery(s);
      while (rs.next()) {

        Blob blob = rs.getBlob("ev_stat");

        ObjectInputStream input = new ObjectInputStream(blob.getBinaryStream());
        result.add((EvStatistic)input.readObject());

      }
      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }

    if (result.size() == 0) {
      return null;
    } else {
      Object[] res = new Object[result.size()];

      for (int i = 0; i < res.length; i++) {
        res[i] = result.get(i);
      }
      return res;
    }
  }

  public EvStatistic[] getStatisticsByNodes(long task_id, int[] nodes) {

    List<EvStatistic> result = new ArrayList<EvStatistic>();
    try {

      if (nodes.length == 0)
        return null;
      String sql_str = "( node_id=" + nodes[0];
      for (int i = 1; i < nodes.length; i++) {
        sql_str += " OR nodes_id=" + nodes[i];
      }
      sql_str += " )";

      Statement stmt = conn.createStatement();

      String s = "SELECT * FROM ev_statistics WHERE " + "task_id='" + task_id
          + "' AND " + sql_str + " ORDER BY iteration, node_id";

      ResultSet rs = stmt.executeQuery(s);
      while (rs.next()) {

        Blob blob = rs.getBlob("ev_stat");

        ObjectInputStream input = new ObjectInputStream(blob.getBinaryStream());
        result.add((EvStatistic)input.readObject());

      }
      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }

    if (result.size() == 0) {
      return null;
    } else {
      EvStatistic[] res = new EvStatistic[result.size()];

      for (int i = 0; i < res.length; i++) {
        res[i] = result.get(i);
      }
      return res;
    }
  }

  public EvStatistic[] getStatisticsByID(long task_id) {
    List<EvStatistic> result = new ArrayList<EvStatistic>();
    try {
      Statement stmt = conn.createStatement();
      String s = "SELECT * FROM ev_statistics WHERE " +
            "task_id='" + task_id + "' ORDER BY iteration, node_id";
      ResultSet rs = stmt.executeQuery(s);
      while (rs.next()) {

        Blob blob = rs.getBlob("ev_stat");

        ObjectInputStream input = new ObjectInputStream(blob.getBinaryStream());
        result.add((EvStatistic)input.readObject());

      }
      rs.close();
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace(System.out);
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }

    if (result.size() == 0) {
      return null;
    } else {
      EvStatistic[] res = new EvStatistic[result.size()];

      for (int i = 0; i < res.length; i++) {
        res[i] = result.get(i);
      }
      return res;
    }
  }

}
